use super::driver::{ctrl, motor};
use crate::{cmd, error::AppErr, task::handler_task::Response};
use cmsis_rtos2_rs::os_kernel_get_tick_count;
use proto_bytes::message::ReqRef;
use utils::MutCell;

pub fn on_request(req: ReqRef) -> Result<Response, AppErr> {
    let cmd = req.cmd();
    match cmd {
        cmd::door::PICK_DOOR => req
            .parse()
            .ok_or(AppErr::Parse)
            .and_then(|req| on_pick_door(req)),

        cmd::door::STRAW_CTRL => req
            .parse()
            .ok_or(AppErr::Parse)
            .and_then(|req| on_straw_ctrl(req)),

        _ => Err(AppErr::InvalidCmd),
    }
}

pub fn on_simple_req(req: ReqRef) -> Result<Response, AppErr> {
    let cmd = req.cmd();
    match cmd {
        cmd::door::PARTS_CTRL => req
            .parse()
            .ok_or(AppErr::Parse)
            .and_then(|req| on_parts_ctrl(req)),

        _ => Err(AppErr::InvalidCmd),
    }
}

struct StrawCtrlCtx {
    open_flag: bool,
    open_tick: u32,
}

static STRAW_CTRL_CTX: MutCell<StrawCtrlCtx> = MutCell::const_new(StrawCtrlCtx {
    open_flag: false,
    open_tick: 0,
});

pub fn on_idle() {
    if STRAW_CTRL_CTX.open_flag
        && ((os_kernel_get_tick_count() - STRAW_CTRL_CTX.open_tick) >= 1 * 60 * 1000)
    {
        ctrl::straw_force_close();
        let ctx = unsafe { STRAW_CTRL_CTX.as_mut() };
        ctx.open_flag = false;
    }
}

fn on_straw_ctrl(ctrl: u8) -> Result<Response, AppErr> {
    
    match ctrl {
        0 => {
            ctrl::straw_open();
            let ctx = unsafe { STRAW_CTRL_CTX.as_mut() };
            ctx.open_flag = true;
            ctx.open_tick = os_kernel_get_tick_count();
        }
        1 => ctrl::straw_close()?,
        _ => return Err(AppErr::Invalid),
    }
    Ok(Response::Empty(()))
}

fn on_pick_door(ctrl: u8) -> Result<Response, AppErr> {
    match ctrl {
        0 => motor::pick_door_open()?,
        1 => motor::pick_door_close()?,
        _ => return Err(AppErr::Invalid),
    };
    Ok(Response::Empty(()))
}

fn on_parts_ctrl((id, ctrl): (u8, u8)) -> Result<Response, AppErr> {
    let n = ((id as u16) << 8) | (ctrl as u16);
    match n {
        0x0100 => ctrl::led1_open(),
        0x0101 => ctrl::led1_close(),
        0x0200 => ctrl::led2_open(),
        0x0201 => ctrl::led2_close(),
        _ => return Err(AppErr::Invalid),
    }
    Ok(Response::Empty(()))
}
